package cn.shiwei.pay.service.impl;

import cn.shiwei.basic.exception.MyException;
import cn.shiwei.order.domain.OrderDetail;
import cn.shiwei.order.domain.OrderPet;
import cn.shiwei.order.mapper.OrderDetailMapper;
import cn.shiwei.order.mapper.OrderPetMapper;
import cn.shiwei.pay.domain.PayAlipayInfo;
import cn.shiwei.pay.domain.PayBill;
import cn.shiwei.pay.domain.PayFlow;
import cn.shiwei.pay.dto.AlipayNotifyDto;
import cn.shiwei.pay.mapper.PayAlipayInfoMapper;
import cn.shiwei.pay.mapper.PayBillMapper;
import cn.shiwei.pay.mapper.PayFlowMapper;
import cn.shiwei.pay.service.IPaySerivce;
import cn.shiwei.pet.domain.Pet;
import cn.shiwei.pet.mapper.PetDetailMapper;
import cn.shiwei.pet.mapper.PetMapper;
import com.alibaba.fastjson.JSON;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.facetoface.models.AlipayTradePrecreateResponse;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collector;
import java.util.stream.Collectors;

@Service
@Transactional
public class PaySerivceImpl implements IPaySerivce {

    @Autowired
    private PetMapper petMapper;

    @Autowired
    private PayAlipayInfoMapper payAlipayInfoMapper;

    @Autowired
    private PayBillMapper payBillMapper;

    @Autowired
    private OrderPetMapper orderPetMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private PayFlowMapper payFlowMapper;


    @Override
    public String toPay(String sn) {
        // 请求支付
        // 参数校验, 订单号
        if (!StringUtils.hasLength(sn)){
            throw new MyException("非法请求");
        }

        // 加载支付单, 订单号对应的支付单
        PayBill payBill = payBillMapper.loadBySn(sn);
        if (payBill == null) {
            throw new MyException("非法请求");
        }

        // 加载配置, 数据来源于表 // 表里只有1个数据id为1, 其实还算号查, 可以在前端调用该接口时传来shopid即可(前端订单页面是可以拿到shopid的(查宠物详情查出来的))
        PayAlipayInfo payAlipayInfo = payAlipayInfoMapper.loadById(1L);
        if (payAlipayInfo == null) {
            throw new MyException("无效的alipay配置, 请联系管理员处理");
        }

        // 支付请求 --------------copy  api----------------------------------
        Factory.setOptions(payAlipayInfo.getOptions());
        try {
            // 2. 发起API调用（以创建当面付收款二维码为例）
            AlipayTradePagePayResponse response = Factory.Payment.Page()
                    // 标题,
                    .pay(payBill.getDigest(), // 标题
                            payBill.getUnionPaySn(), // 订单号
                            payBill.getMoney().toString(), // 金额, 支付宝要String
                            String.format(payAlipayInfo.getReturnUrl(), payBill.getUnionPaySn())); // 同步回调地址, string.format用于替换字符串中的占位符
            // 3. 处理响应或异常
            if (ResponseChecker.success(response)) {
                System.out.println("调用成功");
                System.out.println(response.getBody());
                return response.getBody();
            } else {
                System.err.println("调用失败");
            }
        } catch (Exception e) {
            System.err.println("调用遭遇异常，原因：" + e.getMessage());
            throw new RuntimeException(e.getMessage(), e);
        }
        return "系统繁忙_支付";
        // --------------------copy  api-------------------------------


    }

    @Override
    public PayBill successPage(String sn) {
        if (!StringUtils.hasLength(sn)) {
            throw new MyException("非法访问");
        }
        PayBill payBill = payBillMapper.loadBySn(sn);
        if (payBill == null) {
            throw new MyException("非法访问");
        }
        return payBill;
    }

    @Override
    public String alipayNotify(AlipayNotifyDto payNotifyDto) {

        System.out.println("支付宝回调开始");
         // 校验参数


        // 验签
        // 转成json字符串
        String jsonString = JSON.toJSONString(payNotifyDto);
        // 将json字符串转成map
        Map<String, String> map = JSON.parseObject(jsonString, Map.class);
        //... ... 接收到的所有参数放入一个Map中
        try {
            Boolean aBoolean = Factory.Payment.Common().verifyNotify(map);
            if (!aBoolean) {
                System.out.println("签名验证失败");
                return "fail";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 根据订单号校验信息
        String out_trade_no = payNotifyDto.getOut_trade_no();
        if(!StringUtils.hasLength(out_trade_no)){
            System.out.println("订单号错误");
            return "fail";
        }
        PayBill payBill = payBillMapper.loadBySn(out_trade_no);
        if (payBill == null) {
            System.out.println("订单号错误");
            return "fail";
        }

        // 对比金额是否一致(compareTo比较等于0相同)
        BigDecimal bigDecimal = new BigDecimal(payNotifyDto.getTotal_amount());
        if (payBill.getMoney().compareTo(bigDecimal) != 0){
            System.out.println("支付金额异常");
            return "fail";
        }

        // 比较appid(此处简化代码(库中就一条id, id应该根据订单号查对应shopid, 在查出支付宝的商铺配置)
        PayAlipayInfo payAlipayInfo = payAlipayInfoMapper.loadById((long) 1);
        String app_id = payNotifyDto.getApp_id();
        System.out.println("比较为"+!StringUtils.hasLength(app_id));
        System.out.println("比较为"+!app_id.equals(payAlipayInfo.getAppid()));
        if (!StringUtils.hasLength(app_id) || !app_id.equals(payAlipayInfo.getAppid())){
            System.out.println("appid异常");
            return "fail";
        }

        // 如果支付状态在支付中, 则不处理
        if(payNotifyDto.isTradeWit()){
            System.out.println("支付中");
            return "fail";
        }

        List<OrderDetail> details = orderDetailMapper.loadBySn(out_trade_no);


        // 如果支付成功, 支付超时, 支付取消, 则修改支付单, 业务单的状态
        OrderPet orderPet = orderPetMapper.loadBySn(out_trade_no);
        if(payNotifyDto.isTradeSuccess()){
            // 如果成功
            payBill.setState(PayBill.STATUS_SUCCESS);
            orderPet.setState(OrderPet.STATUS_PAID_DELIVERY);
        } else if (payNotifyDto.isTradeExpire()) {
            // 如果超时
            payBill.setState(PayBill.STATUS_TIMEOUT_OR_REFUND);
            orderPet.setState(OrderPet.STATUS_AUTO_CANCEL);
            // 拿到所有宠物id, 为该订单的所有宠物退库存
            List<Long> petIds = details.stream().map(orderDetail -> orderDetail.getProduck_id()).collect(Collectors.toList());
            List<Pet> pets = petMapper.patchLoad(petIds, Pet.ON_SALE_STATUS);
           pets.forEach(pet -> {
               pet.setRepertory(pet.getRepertory() + 1);
               petMapper.update(pet);
           }) ;
        } else {
            System.out.println("交易异常, 请联系客服处理");
            return "fail";
        }

        PayFlow payFlow = new PayFlow();
        BeanUtils.copyProperties(payNotifyDto, payFlow);
        payFlowMapper.save(payFlow);

        System.out.println("支付宝回调结束");
        // 支付宝的接口在没有返回success的情况下会多次调用该接口, 如果验签失败就让他多次调用, 成功就不要让他多次掉用
        return "success";
    }
}
